#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/sysfs.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/sched.h>  
#include <asm/io.h>
#include <linux/gpio.h> 
#include <linux/poll.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include "my_key_input.h"

static struct my_key_dev* my_key = NULL;

/*********************按键中断服务函数，在中断的上半段执行***********************/
irqreturn_t my_key_irq_handler(int irq, void* dev)
{
	struct my_key_dev* key = (struct my_key_dev*)dev;
	mod_timer(&key->timer, jiffies + msecs_to_jiffies(10)); // 定时器延时10毫秒
	return IRQ_RETVAL(IRQ_HANDLED);
}
/******************************定时器到期执行函数****************************/
void timer_fun(unsigned long data)
{
	int val = 0;
	struct my_key_dev* dev = (struct my_key_dev*)data;
	val = gpio_get_value(dev->key_desc.gpio);
	if (val == 1) {  // 按键按下
		input_report_key(dev->key_input_dev, dev->key_desc.code, val);
		input_sync(dev->key_input_dev);
		dev->key_desc.key_push_cnt++;
	}
	else {	// 按键松开
		input_report_key(dev->key_input_dev, dev->key_desc.code, val);
		input_sync(dev->key_input_dev);
		dev->key_desc.key_release_cnt++;
	}
}

static int key_gpio_init(struct my_key_dev* dev, struct platform_device* pdev)
{
	int ret = 0;
	struct device_node* n;
	n = of_find_node_by_path(KEY_DT_PATH);  // 获取按键设备树节点
	if (NULL == n) {
		printk(KERN_ERR "find key node error by %s\n", KEY_DT_PATH);
		return -EINVAL;		
	}
	dev->key_desc.gpio = of_get_named_gpio(n, "key",0);  // 获取gpio编号
	if (dev->key_desc.gpio < 0) {
		printk(KERN_ERR "can't get key number\n");
		return -EINVAL;
	}
	ret = gpio_request(dev->key_desc.gpio, NAME);  // 申请gpio
	if (ret < 0) {
		printk(KERN_ERR "request key gpio error\n");
		return -EINVAL;		
	}
	gpio_direction_input(dev->key_desc.gpio);  // gpio设置为输入
	dev->key_desc.irq = irq_of_parse_and_map(n, 0); // 获取虚拟中断号
	if (0 == dev->key_desc.irq) {
		printk(KERN_ERR "can't parse and map irq\n");
		ret = -1;
		goto free_gpio;
	}
	// 读取code的属性值
	ret = of_property_read_u32_index(n, "code", 0, &dev->key_desc.code);
	if (ret < 0) {
		printk(KERN_ERR "can't parse and map irq\n");
		goto free_gpio;
	}
	ret = request_irq(dev->key_desc.irq, my_key_irq_handler, 
							IRQ_TYPE_EDGE_BOTH, NAME, dev);
	if (ret < 0) {
		printk(KERN_ERR "request %s irq failed\n", NAME);
		goto free_gpio;		
	}
	return 0;
free_gpio:
	gpio_free(dev->key_desc.gpio);
	return ret;
} 

/***************************模块初始化**************************************/
static int my_key_probe(struct platform_device* dev)
{
	int ret = 0;

	// 分配设备结构体内存并将分配的内存清0
	my_key = kzalloc(sizeof(struct my_key_dev), GFP_KERNEL);
	if (NULL == my_key) {
		printk(KERN_ERR "kzalloc failed\n");
		return -ENOMEM;
	}

	init_timer(&my_key->timer);  // 初始化定时器
	my_key->timer.function = timer_fun;
	my_key->timer.data = (unsigned long)my_key;
	add_timer(&my_key->timer);   // 注册定时器

	ret = key_gpio_init(my_key, dev);
	if (ret < 0) goto timer_del;

	my_key->key_input_dev = input_allocate_device(); // 分配input_dev结构体
	if (NULL == my_key->key_input_dev) {
		printk(KERN_ERR "allocate input device failed\n");
		ret = -ENOMEM;
		goto timer_del;
	}
	my_key->key_input_dev->name = NAME;
	set_bit(EV_KEY, my_key->key_input_dev->evbit);  // 产生按键事件
	set_bit(EV_REP, my_key->key_input_dev->evbit);  // 产生重复事件
	// 产生KEY_0按键
	set_bit(my_key->key_desc.code, my_key->key_input_dev->keybit);  
	ret = input_register_device(my_key->key_input_dev);
	if (ret < 0) {
		printk(KERN_ERR "input device register failed\n");
		goto free_input_device;
	}
	printk(KERN_INFO "my_key module init OK\n");
	return 0;

free_input_device:
	input_free_device(my_key->key_input_dev);
timer_del:
	del_timer(&my_key->timer);   // 删除定时器
	kfree(my_key);
	my_key = NULL;
    return ret;
}
/********************模块注销************************/
static int my_key_remove(struct platform_device* dev)
{
	input_unregister_device(my_key->key_input_dev);
	input_free_device(my_key->key_input_dev);
	gpio_free(my_key->key_desc.gpio);
	free_irq(my_key->key_desc.irq, my_key);
	del_timer(&my_key->timer);   // 删除定时器
	kfree(my_key);
	my_key = NULL;
	printk(KERN_INFO "my_key module exit\n");
	return 0;
}

// 定义设备和驱动匹配需要的of_device_id匹配表变量，
static const struct of_device_id my_key_of_match[] = {
	{ .compatible = "my-key" },   //  兼容属性，需要与设备树中的兼容属性一致
	{ /* Sentinel */ }            // 最后一个元素一定为空
};
MODULE_DEVICE_TABLE(of, my_key_of_match);
// 定义注册驱动时需要的platform_driver结构体变量
static struct platform_driver my_key_platform_driver = {
	.driver = {
		.name = "imx6ull-my-led",   // 设置驱动的名称
		 // 驱动的设备的匹配数组信息，一个驱动可以和多个设备匹配
		.of_match_table = my_key_of_match,
	},
	.probe = my_key_probe,    // 设置初始化probe函数，驱动和设备匹配成功后此函数会执行
	.remove = my_key_remove,  // 设置退出remove函数
};

/**********************模块初始化****************************/
static int __init my_key_init(void)
{
	int ret = 0;
	ret = platform_driver_register(&my_key_platform_driver);
	if (ret < 0) printk(KERN_ERR "my_key register platform driver error\n");
	return ret;
}
/***********************模块注销***************************/
static void __exit my_key_exit(void)
{
	platform_driver_unregister(&my_key_platform_driver);
}

module_init(my_key_init);
module_exit(my_key_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("liyang.plus@foxmail.com");
MODULE_VERSION("v1.00");